#include "../LogSystem/1_util.hpp"
#include "../LogSystem/2_level.hpp"
#include "../LogSystem/3_msg.hpp"
#include "../LogSystem/4_format.hpp"
#include "../LogSystem/5_logSink.hpp"
#include "../LogSystem/6_buffer.hpp"

int main1()
{
    // std::cout << senlog::util::Date::getTime() << std::endl;

    // std::string pathname = "./abc/def/a.txt";
    // senlog::util::File::createDirectory(senlog::util::File::path(pathname));//创建a.txt的父级目录：./abc/def/

    // std::cout << senlog::LogLevel::tostring(senlog::LogLevel::value::ERROR) << std::endl;//tostring成员函数需要先定义对象使用：解决：static

    senlog::LogMsg msg(senlog::LogLevel::value::INFO, 12, "root", "main.cc", "格式化模块测试~");
    senlog::Formatter fmt;
    std::string str = fmt.format(msg);

    senlog::LogSink::ptr stdout_lsp = senlog::SinkFactory::create<senlog::StdoutLogSink>();
    senlog::LogSink::ptr file_lsp = senlog::SinkFactory::create<senlog::FileLogSink>("./logfile/test.log");
    senlog::LogSink::ptr roll_lsp = senlog::SinkFactory::create<senlog::RollLogSink>("./logfile/roll", 1024 * 1024);

    stdout_lsp->Log(str.c_str(), str.size());
    file_lsp->Log(str.c_str(), str.size());

    size_t cursize = 0;
    while (cursize < 1024 * 1024 * 10) // 写入10M，理论上会有10个文件
    {

        roll_lsp->Log(str.c_str(), str.size());
        cursize += str.size();
    }
    return 0;
}

/*
    扩展一个 以时间作为日志滚动切换类型的日志落地模块
        以时间段作为滚动标准    time(nullptr) % 60
*/
enum class TimeGap // 定义不同的单位，方便用户选择
{
    GAP_SECOND,
    GAP_MINUTE,
    GAP_HOUR,
    GAP_DAY,
};
class RollByTimeLogSink : public senlog::LogSink
{
private:
    std::string _basename;
    std::ofstream _ofs;
    size_t _cur_gap;  // 当前时间段是第几个文件
    size_t _gap_size; // 分段大小
private:
    std::string createNewFileName()
    {
        time_t t = senlog::util::Date::getTime(); // 获取当前时间
        struct tm lt;
        localtime_r(&t, &lt);
        std::stringstream file_new_name;
        file_new_name << _basename;
        file_new_name << "-";
        file_new_name << lt.tm_year + 1900;
        file_new_name << lt.tm_mon + 1;
        file_new_name << lt.tm_mday;
        file_new_name << lt.tm_hour;
        file_new_name << lt.tm_min;
        file_new_name << lt.tm_sec;
        file_new_name << ".log(Time)";
        // senlog::util::File::createDirectory(senlog::util::File::path(_basename));
        return file_new_name.str();
    }

public:
    RollByTimeLogSink(const std::string &basename, TimeGap timegap)
        : _basename(basename)
    {
        switch (timegap)
        {
        case TimeGap::GAP_SECOND:
            _gap_size = 1;
            break;
        case TimeGap::GAP_MINUTE:
            _gap_size = 5;
            break;
        case TimeGap::GAP_HOUR:
            _gap_size = 3600;
            break;
        case TimeGap::GAP_DAY:
            _gap_size = 3600 * 24;
            break;
        }
        _cur_gap = senlog::util::Date::getTime() / _gap_size; // 创建当前的时间段
        std::string filename = createNewFileName();           // 基于basename创建新的filename
        senlog::util::File::createDirectory(senlog::util::File::path(filename));
        _ofs.open(filename, std::ios::binary | std::ios::app); // 使用流式文件创建（打开）filename文件
        assert(_ofs.is_open());                                // 打开成功
    }
    virtual void Log(const char *data, size_t len)
    {
        // 根据构造函数所打开好的流式文件_ofs，进行数据的写入
        // 首先需要判断时间是否满足
        size_t num = senlog::util::Date::getTime() / _gap_size;
        if (num != _cur_gap) // 非当前时间段，说明需要创建新文件
        {
            _cur_gap = num;
            // 满足时间要求
            _ofs.close();
            std::string newfilename = createNewFileName();
            _ofs.open(newfilename, std::ios::binary | std::ios::app);
            assert(_ofs.is_open());
            std::cout << "--------Test: 创建新文件-------" << std::endl;
        }
        _ofs.write(data, len);
        _ofs.good();
    }
};
int main2()
{
    senlog::LogMsg msg(senlog::LogLevel::value::INFO, 12, "root", "main.cc", "格式化模块测试~");
    senlog::Formatter fmt;
    std::string str = fmt.format(msg);

    senlog::LogSink::ptr time_lsp = senlog::SinkFactory::create<RollByTimeLogSink>("./logfile/roll-", TimeGap::GAP_MINUTE);
    while (1)
    {
        time_lsp->Log(str.c_str(), str.size());
        sleep(1);
    }
    return 0;
}

#include "logger.hpp"

int main3()
{
    // 这里就体现使用建造者模式的重要性（使用各个组件创建一个复杂对象）
    // 用户创建一个logger对象 需要太多的参数，使用建造者模式简化创建步骤
    std::string logger_name = "sync_logger";
    senlog::Formatter::ptr fmt(new senlog::Formatter("[%d{%H:%M:%S}][%c][%f:%l][%p]%t%m%n"));

    // 三个落地方式器
    senlog::LogSink::ptr stdout_lsp = senlog::SinkFactory::create<senlog::StdoutLogSink>();
    senlog::LogSink::ptr file_lsp = senlog::SinkFactory::create<senlog::FileLogSink>("./logfile/test.log");
    senlog::LogSink::ptr roll_lsp = senlog::SinkFactory::create<senlog::RollLogSink>("./logfile/roll", 1024 * 1024);
    std::vector<senlog::LogSink::ptr> sinks = {stdout_lsp, file_lsp, roll_lsp};

    senlog::Logger::ptr logger(new senlog::SyncLogger(logger_name, senlog::LogLevel::value::WARN, fmt, sinks));

    // 测试

    logger->debug(__FILE__, __LINE__, "%s", "测试日志");
    logger->info(__FILE__, __LINE__, "%s", "测试日志");

    logger->warn(__FILE__, __LINE__, "%s", "测试日志");
    logger->error(__FILE__, __LINE__, "%s", "测试日志");
    logger->fatal(__FILE__, __LINE__, "%s", "测试日志");

    size_t cursize = 0, count = 0;
    std::string str = "测试日志-";
    while (cursize < 1024 * 1024 * 10) // 写入10M，理论上会有10个文件
    {
        logger->fatal(__FILE__, __LINE__, "测试日志-%d", count++);
        cursize += 20;
    }
}

int main4()
{
    std::unique_ptr<senlog::LoggerBuilder> builder(new senlog::LocalLoggerBuilder());
    builder->buildLoggerType(senlog::LoggerType::SYNC_LOGGER);
    builder->buildLimitValue(senlog::LogLevel::value::WARN);
    builder->buildLoggerName("sync_logger");
    builder->buildFormatterPtr("%m%n");
    builder->buildSink<senlog::FileLogSink>("./logfile/test.log");
    builder->buildSink<senlog::StdoutLogSink>();

    senlog::Logger::ptr logger = builder->build();

    // 测试

    logger->debug(__FILE__, __LINE__, "%s", "测试日志");
    logger->info(__FILE__, __LINE__, "%s", "测试日志");

    logger->warn(__FILE__, __LINE__, "%s", "测试日志");
    logger->error(__FILE__, __LINE__, "%s", "测试日志");
    logger->fatal(__FILE__, __LINE__, "%s", "测试日志");

    size_t cursize = 0, count = 0;
    std::string str = "测试日志-";
    while (cursize < 1024 * 1024 * 10) // 写入10M，理论上会有10个文件
    {
        logger->fatal(__FILE__, __LINE__, "测试日志-%d", count++);
        cursize += 20;
    }
    return 0;
}

int main5()
{
    // 测试异步缓冲区
    //  bash::  md5sum test.log  以文件内容返回一串唯一数字

    std::ifstream ifs("./logfile/test.log", std::ios::binary);
    if (ifs.is_open() == false)
        return -1;

    ifs.seekg(0, std::ios::end);
    size_t f_size = ifs.tellg(); // 文件大小？

    ifs.seekg(0, std::ios::beg);

    std::string body;
    body.resize(f_size);
    ifs.read(&body[0], f_size);
    if (ifs.good() == false)
    {
        std::cout << "read error" << std::endl;
        return -1;
    }
    ifs.close();

    senlog::Buffer buffer;
    for (int i = 0; i < body.size(); i++)
    {
        buffer.push(&body[i], 1);
    }

    std::ofstream ofs(("logfile/temp.log"), std::ios::binary);
    size_t num = buffer.readableSize(); //
    for (int i = 0; i < num; i++)
    {
        ofs.write(buffer.readableBegin(), 1);
        buffer.shiftReadIdx(1);
    }
    ofs.close();
    return 0;
}


int main()
{
    std::unique_ptr<senlog::LoggerBuilder> builder(new senlog::LocalLoggerBuilder());
    builder->buildLoggerType(senlog::LoggerType::ASYN_LOGGER);
    builder->buildEnableUnsafe();
    builder->buildLimitValue(senlog::LogLevel::value::WARN);
    builder->buildLoggerName("Async_logger");
    builder->buildFormatterPtr("[%c]%m%n");
    builder->buildSink<senlog::FileLogSink>("./logfile/async_log_test.log");
    builder->buildSink<senlog::StdoutLogSink>();

    senlog::Logger::ptr logger = builder->build();

    // 测试

    logger->debug(__FILE__, __LINE__, "%s", "测试日志");
    logger->info(__FILE__, __LINE__, "%s", "测试日志");

    logger->warn(__FILE__, __LINE__, "%s", "测试日志");
    logger->error(__FILE__, __LINE__, "%s", "测试日志");
    logger->fatal(__FILE__, __LINE__, "%s", "测试日志");

    size_t cursize = 0, count = 0;
    std::string str = "测试日志-";
    while (cursize < 1024 * 1024 * 10) // 写入10M，理论上会有10个文件
    {
        logger->fatal(__FILE__, __LINE__, "测试日志-%d", count++);
        cursize += 20;
    }
}